/**
 * 加解密工具类
 */
const keyStr = atob('c2ZtYXAxMjM=')
const ivStr = atob('MTIzc2ZtYXA=')
const GLOBAL_EXTENT = 20037508.34
const TILE_SIZE = 256
const BASE_URL = 'http://localhost:18081'
let self = null

class AesUtil {
  constructor() {
    this.key = CryptoJS.enc.Utf8.parse(keyStr);  //十六位十六进制数作为密钥
    this.iv = CryptoJS.enc.Utf8.parse(ivStr);   //十六位十六进制数作为密钥偏移量
  }
  /**
   * 加密方法
   * @param word
   * @return {string}
   */
  encrypt(word) {
    let srcs = CryptoJS.enc.Utf8.parse(word);
    let encrypted = CryptoJS.AES.encrypt(srcs, this.key, { iv: this.iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.ciphertext.toString().toUpperCase();
  }

  /**
   * 解密方法
   * @param word
   * @return {string}
   */
  decrypt(word) {
    const encryptedHexStr = CryptoJS.enc.Hex.parse(word);
    const srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
    const decrypt = CryptoJS.AES.decrypt(srcs, this.key, {iv: this.iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7});
    const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
  }
}

class TileUtil {
  constructor(map, ak = '664e42802f604c35b8afa2de864c55cb') {
    this.map = map
    this.ak = ak
    let resolutions = []
    let res = (GLOBAL_EXTENT  * 2) / TILE_SIZE
    for(let i = 0; i < 23; i++) {
      resolutions.push(res)
      res = res / 2
    }
    this._resolutions = resolutions
    this._aesUtil = new AesUtil()
    this._tileData = {}
    this._highlightLayer = null
    this._hightlightData = []
    this._colorDict = {
      5452: {
        strokeStyle: '#00f',
        lineWidth: 2,
        fillStyle: 'rgba(0,0,255,0.2)'
      },
      5475: {
        strokeStyle: '#ffa200',
        lineWidth: 2,
        fillStyle: 'rgba(255,162,0,0.2)'
      },
      5453: {
        strokeStyle: '#00f',
        lineWidth: 2,
        fillStyle: 'rgba(0,0,255,0.2)'
      },
      5379: {
        strokeStyle: '#ffa200',
        lineWidth: 2,
        fillStyle: 'rgba(255,162,0,0.2)'
      }
    }
    self = this
  }
  /**
   * 获取切片位置
   * @param z
   * @param x
   * @param y
   * @return {*}
   */
  _getTilePos(z, x, y) {
    const res = this._resolutions[z] * TILE_SIZE
    const [xOriginMin, yOriginMax] =[-GLOBAL_EXTENT, GLOBAL_EXTENT]
    let [xmin, ymax] = [0, 0]
    xmin = xOriginMin + (res  * x)
    ymax = yOriginMax - (res * y)
    return this.map.getPixelFromCoordinate([xmin, ymax])
  }
  /**
   * 获取视图内的切片索引
   * @param z
   * @param xmin
   * @param ymin
   * @param xmax
   * @param ymax
   * @return {number[]}
   */
  _getExtentTiles(z, [xmin, ymin, xmax, ymax]) {
    const res = this._resolutions[z] * TILE_SIZE
    const [xOriginMin, yOriginMax] =[-GLOBAL_EXTENT, GLOBAL_EXTENT]
    const x1 = Math.ceil((xmin - xOriginMin) / res)
    const x2 = Math.floor((xmax - xOriginMin) / res)
    const y1 = Math.ceil((yOriginMax - ymax) / res)
    const y2 = Math.floor((yOriginMax - ymin) / res)
    return [x1, y1, x2, y2]
  }
  /**
   * 绘制AOI切片
   * @param z
   * @param x
   * @param y
   * @return {HTMLCanvasElement}
   */
  _drawAoiTile(z, x, y, isHighlight = false) {
    const params = this._aesUtil.encrypt(JSON.stringify({x, y, z}))
    const request = new XMLHttpRequest();
    request.open('GET', `${BASE_URL}/tile/aoi?ak=${this.ak}&params=${params}`, false);
    request.send(null);
    const canvas = document.createElement('canvas')
    canvas.width = TILE_SIZE
    canvas.height = TILE_SIZE
    const ctx = canvas.getContext('2d')
    ctx.strokeStyle = isHighlight ? '#0ff' : '#f00'
    ctx.lineWidth = isHighlight ? 3 : 2
    ctx.fillStyle = isHighlight ? 'rgba(0, 255, 255, 0.2)' :'rgba(255, 0, 0, 0.2)'
    if (request.status === 200) {
      const res = JSON.parse(request.responseText)
      if(res.code === 200) {
        let data = JSON.parse(this._aesUtil.decrypt(res.data))
        if(isHighlight) {
          data = data.filter(t => self._hightlightData.includes(t.id))
        }
        data.forEach(({id, geom}) => {
          if(!isHighlight && self._colorDict[id]) {
            ctx.strokeStyle = self._colorDict[id].strokeStyle || '#f00'
            ctx.lineWidth = self._colorDict[id].lineWidth ||  2
            ctx.fillStyle = self._colorDict[id].fillStyle || 'rgba(255, 0, 0, 0.2)'
          }
          ctx.beginPath()
          for(let i = 0; i < geom.length; i++) {
            const [x, y] = geom[i]
            i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)
          }
          ctx.closePath()
          ctx.fill()
          ctx.stroke()
        })
      } else {
        throw new Error(res.msg)
      }
    }
    return canvas
  }
  /**
   * 绘图函数
   * @param extent
   * @param resolution
   * @param pixelRatio
   * @param size
   * @param projection
   * @return {HTMLCanvasElement}
   */
  canvasFunction(extent, resolution, pixelRatio, size, projection) {
    const [width, height] = size
    const mapSize = self.map.getSize()
    const zoom = self.map.getView().getZoom()
    if(zoom >= 14) {
      const [xmin, ymin, xmax, ymax] = self._getExtentTiles(zoom, extent)
      const canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;
      const ctx = canvas.getContext('2d');
      const [deltX, deltY] = [(size[0] - mapSize[0]) / 2, (size[1] - mapSize[1]) / 2];
      for (let i = xmin; i <= xmax; i++) {
        for (let j = ymin; j <= ymax; j++) {
          let [x, y] = self._getTilePos(zoom, i, j)
          x += deltX
          y += deltY
          const key = `${zoom}-${i}-${j}`
          let img = null
          if(!self._tileData[key]) {
            img = self._drawAoiTile(zoom, i, j)
            self._tileData[key] = img
          } else {
            img = self._tileData[key]
          }
          ctx.drawImage(img, x, y)
        }
      }
      return canvas
    }
  }

  _canvasFunction(extent, resolution, pixelRatio, size, projection) {
    const [width, height] = size
    const mapSize = self.map.getSize()
    const zoom = self.map.getView().getZoom()
    if(zoom >= 14) {
      const [xmin, ymin, xmax, ymax] = self._getExtentTiles(zoom, extent)
      const canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;
      const ctx = canvas.getContext('2d');
      const [deltX, deltY] = [(size[0] - mapSize[0]) / 2, (size[1] - mapSize[1]) / 2];
      for (let i = xmin; i <= xmax; i++) {
        for (let j = ymin; j <= ymax; j++) {
          let [x, y] = self._getTilePos(zoom, i, j)
          x += deltX
          y += deltY
          let img = self._drawAoiTile(zoom, i, j, true)
          ctx.drawImage(img, x, y)
        }
      }
      return canvas
    }
  }
  /**
   * 获取高亮数据
   * @param coords
   * @private
   */
  _getHighlightData(coords, ids = []) {
    self._hightlightData = []
    const params = self._aesUtil.encrypt(JSON.stringify({coords, ids}))
    const request = new XMLHttpRequest();
    request.open('GET', `${BASE_URL}/tile/aoi/query?ak=${this.ak}&params=${params}`, false);
    request.send(null);
    if (request.status === 200) {
      const res = JSON.parse(request.responseText)
      if (res.code === 200) {
        const data = JSON.parse(this._aesUtil.decrypt(res.data))
        self._hightlightData = data.map(d => d.id)
      }
    }
  }
  /**
   * 根据坐标高亮
   * @param coords
   */
  highlightByCoords(coords) {
    if(self._highlightLayer) {
      self.map.removeLayer(self._highlightLayer)
    }
    self._getHighlightData(coords)
    if(self._hightlightData.length > 0) {
      self._highlightLayer = new ol.layer.Image({
        source: new ol.source.ImageCanvas({
          canvasFunction: self._canvasFunction
        })
      })
      self.map.addLayer(self._highlightLayer)
    }
  }

  highlightByIds(ids = []) {
    if(self._highlightLayer) {
      self.map.removeLayer(self._highlightLayer)
    }
    self._getHighlightData([], ids)
    if(self._hightlightData.length > 0) {
      self._highlightLayer = new ol.layer.Image({
        source: new ol.source.ImageCanvas({
          canvasFunction: self._canvasFunction
        })
      })
      self.map.addLayer(self._highlightLayer)
    }
  }

  clearHighlight() {
    if(self._highlightLayer) {
      self.map.removeLayer(self._highlightLayer)
    }
  }
}
export default TileUtil